/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014-2016 abel533@gmail.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package tk.mybatis.mapper.mapperhelper;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;

import tk.mybatis.mapper.entity.Config;
import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.entity.EntityTable;
import tk.mybatis.mapper.entity.NestdEntity;
import tk.mybatis.mapper.entity.NestdEntityContext;
import tk.mybatis.mapper.util.StringUtil;

/**
 * 
 * title: SqlNestdHelper.java 
 * 嵌套表常用SQL拼接的方法
 * 
 * @author rplees
 * @email rplees.i.ly@gmail.com
 * @created Jun 29, 2016 2:21:45 PM
 */
public class SqlNestdHelper {
	static List<String> keyword = null;
	
	static {
		List<String> kw = new ArrayList<String>();
		InputStream is = SqlNestdHelper.class.getResourceAsStream("keyword.mysql");
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		
		try {
			String line = br.readLine();
			while (null != line) {
				line = br.readLine();
				if(null != line) {
					String[] split = StringUtils.split(line, ",");
					if(split != null && split.length > 0) {
						for (String string : split) {
							if(StringUtils.isNotBlank(string))
								kw.add(string);
						}
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		SqlNestdHelper.keyword = Collections.unmodifiableList(kw);
	}
	
	public static Config config = new Config();
   
	/**
	 * 是否是数据库保留字 
	 * @param s
	 * @return
	 */
	public static boolean isKeyword(String s) {
		return keyword.contains(s.toUpperCase());
	}
	
	public static String doKeyword(String s) {
		if(isKeyword(s)) {
			return "`" + s + "`";
		}
		
		return s;
	}
	
	public static void checkAndGetAllColumns(Class<?> entityClass, StringBuilder builder, boolean isRoot, NestdEntityContext context) {
		EntityTable entityTable = EntityHelper.getEntityTable(entityClass);
		if(! entityTable.hasNestedTableSelect()) {
			return;
		}
		StringBuilder sql = new StringBuilder();
		
		for (NestdEntity nestdEntity : entityTable.getNestdEntitys()) {
			if(isRoot) {
				context.clear();
			}
			context.record(nestdEntity);
			
			sql.append(SqlHelper.getAllColumns(nestdEntity.getEntityTable().getEntityClass(), 
					context.getAliasSuffix(), false, context)).append(",");
		}
		
		builder.append(sql);
	}
	
	public static String checkIfExistNestedTable(Class<?> entityClass) {
    	EntityTable entityTable = EntityHelper.getEntityTable(entityClass);
    	if(!entityTable.hasNestedTableSelect()) {
    		return "";
    	}
    	StringBuffer buffer = new StringBuffer();
    	_checkIfExistNestedTable(buffer, entityTable, true, new NestdEntityContext(entityClass));
    	return buffer.substring(0, buffer.length() - 1);
    }
	
	static void _checkIfExistNestedTable(StringBuffer buffer, EntityTable entityTable, boolean isRoot, NestdEntityContext context) {
		if(! entityTable.hasNestedTableSelect()) {
			return;
		}
		
    	for (NestdEntity nestdEntity : entityTable.getNestdEntitys()) {
    		if(isRoot) {
    			context.clear();
    		}
    		context.record(nestdEntity);
    		buffer.append(SqlHelper.INDENTATION_SEPARATOR)
    			.append(nestdEntity.getLeftJoinOnTmpl(context.getPreAliasSuffix(), context, config))
    			.append(" ").append(SqlHelper.SPLIT_ENTER_SEPARATOR);
    		
    		_checkIfExistNestedTable(buffer, nestdEntity.getEntityTable(), false, context);
		}
	}
	
	public static String whereAllIfColumnsNestedTable(Class<?> entityClass,boolean empty, StringBuilder sql, boolean isRoot, NestdEntityContext context) {
		EntityTable entityTable = EntityHelper.getEntityTable(entityClass);
		if (!entityTable.hasNestedTableSelect()) {
			return "";
		}
		
		for (NestdEntity nestdEntity : entityTable.getNestdEntitys()) {
			if(isRoot) {
				context.clear();
			}
			
			context.record(nestdEntity);
			whereOneNestdEntity(nestdEntity, sql, empty, context);
		}
		
		return sql.toString();
	}
	
	public static void whereOneNestdEntity(NestdEntity nestdEntity, StringBuilder sql, boolean empty, NestdEntityContext context) {
		EntityTable nestedEntityTable = nestdEntity.getEntityTable();
		Set<EntityColumn> entityClassColumns = nestedEntityTable.getEntityClassColumns();
		for (EntityColumn column : entityClassColumns) {
			sql.append(SqlHelper.INDENTATION_SEPARATOR).append(SqlHelper.getIfNotNull(
					context.getOGNLTestSuffix(),
					column,
					" AND "+ column.getColumnEqualsHolderWithTableAlias(SqlNestdHelper.doKeyword(context.getAliasSuffix()), context.getOGNLTestSuffix()),
					empty)).append(SqlHelper.SPLIT_ENTER_SEPARATOR);
		}
		
		whereAllIfColumnsNestedTable(nestdEntity.getEntityTable().getEntityClass(), empty, sql, false, context);
	}
	
	 public static String getTableAliasIfNeed(Class<?> entityClass) {
    	EntityTable entityTable = EntityHelper.getEntityTable(entityClass);
    	String suffix = "";
    	if(entityTable.hasNestedTableSelect()) {
    		suffix = tableName(entityTable, config);
    	}
    	
    	return suffix;
    }
	 
	/**
	 * 获取实体类的表名
	 *
	 * @param entityClass
	 * @return
	 */
	public static String tableName(Class<?> entityClass, Config config) {
		EntityTable entityTable = EntityHelper.getEntityTable(entityClass);
		return tableName(entityTable, config);
	}

	/**
	 * 获取实体类的表名
	 *
	 * @param EntityTable
	 * @return
	 */
	public static String tableName(EntityTable entityTable, Config config) {
		String prefix = entityTable.getPrefix();
		if (StringUtil.isEmpty(prefix)) {
			// 使用全局配置
			prefix = config.getPrefix();
		}
		if (StringUtil.isNotEmpty(prefix)) {
			return prefix + "." + entityTable.getName();
		}
		return entityTable.getName();
	}
}